/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.debugger.support.nodes; import java.awt.Image; import java.awt.Toolkit; import java.io.IOException; import java.beans.BeanInfo; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.reflect.InvocationTargetException; import java.util.ResourceBundle; import org.openide.actions.DeleteAction; import org.openide.actions.PropertiesAction; import org.openide.actions.ToolsAction; import org.openide.debugger.Debugger; import org.openide.debugger.Watch; import org.openide.debugger.DebuggerException; import org.openide.TopManager; import org.openide.util.NbBundle; import org.openide.nodes.BeanNode; import org.openide.nodes.Node; import org.openide.nodes.Children; import org.openide.nodes.AbstractNode; import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; import org.openide.util.actions.SystemAction; import org.netbeans.modules.debugger.support.actions.CreateVariableAction; import org.netbeans.modules.debugger.support.actions.CreateVariableCookie; import org.netbeans.modules.debugger.support.actions.GetVariableCookie; import org.netbeans.modules.debugger.support.actions.CreateVariableAccessBreakpointAction; import org.netbeans.modules.debugger.support.actions.CreateVariableModificationBreakpointAction; import org.netbeans.modules.debugger.support.DebuggerAdapter; import org.netbeans.modules.debugger.support.AbstractVariable; import org.netbeans.modules.debugger.support.util.Utils; /** * This class represents variable as a Node. * * @author Jan Jancura */ public class VariableNode extends AbstractNode implements GetVariableCookie, CreateVariableCookie { /** generated Serialized Version UID */ static final long serialVersionUID = -4167730461290769518L; protected static String ICON_BASE = "/org/netbeans/core/resources/variable"; // NOI18N public static final String PROP_MODIFIERS = "modifiers"; // NOI18N public static final String PROP_INNER_TYPE = "innerType"; // NOI18N public static final String PROP_BASE_INDEX = "baseIndex"; // NOI18N public static final String PROP_DISPLAYED_LENGTH = "displayedLength"; // NOI18N private static ResourceBundle bundle; // variables ................................................................. /** Where to add variables. */ private VariableHome variableHome; private boolean isRoot = false; protected AbstractVariable variable = null; protected transient Debugger debugger; private PropertyChangeListener pcl; /** First index of an array to be displayed. */ private int baseIndex = 0; /** Number of field of an array to be displayed. */ private int displayedLength = 100; private boolean isArray; // init ...................................................................... /** * Creates empty Variable context. */ public VariableNode ( VariableHome variableHome, AbstractVariable variable, boolean isRoot ) { super ( variable.isLeaf () ? Children.LEAF : new VariableContextChildren (variableHome) ); this.variableHome = variableHome; this.isRoot = isRoot; this.variable = variable; isArray = variable.isArray (); init (); } /** * Creates empty Variable context. */ public VariableNode ( VariableHome variableHome, AbstractVariable variable ) { this (variableHome, variable, false); } protected void init () { variable.addPropertyChangeListener (pcl = new PropertyChangeListener () { public void propertyChange (PropertyChangeEvent e) { parameterChanged (e); } }); setDisplayName (getName ()); setName (getName ()); setIconBase(ICON_BASE); // obtain debugger reference try { debugger = TopManager.getDefault ().getDebugger (); } catch (DebuggerException exc) { TopManager.getDefault ().notifyException (exc); } createProperties (); getCookieSet ().add (this); changeChildren (); } /** deserializes object */ private void readObject (java.io.ObjectInputStream obis) throws java.io.IOException, ClassNotFoundException, java.io.NotActiveException { obis.defaultReadObject (); init (); } // implementation of Node .................................................... /** Creates properties for this node */ protected void createProperties () { // default sheet with "properties" property set // NOI18N Sheet sheet = Sheet.createDefault (); Sheet.Set ps = sheet.get (Sheet.PROPERTIES); ps.put (new PropertySupport.ReadOnly ( Watch.PROP_VARIABLE_NAME, String.class, getLocalizedString ("PROP_watch_name"), getLocalizedString ("HINT_watch_name") ) { public Object getValue () { return variable.getVariableName (); } }); createCommonProperties (bundle, ps); // and set new sheet setSheet (sheet); } /** Getter for set of actions that should be present in the * popup menu of this node. This set is used in construction of * menu returned from getContextMenu and specially when a menu for * more nodes is constructed. * * @return array of system actions that should be in popup menu */ public SystemAction[] getActions () { if (isRoot) return new SystemAction[] { // CreateVariableModificationBreakpointAction.get (CreateVariableModificationBreakpointAction.class), // CreateVariableAccessBreakpointAction.get (CreateVariableAccessBreakpointAction.class), // null, SystemAction.get (DeleteAction.class), null, SystemAction.get (ToolsAction.class), SystemAction.get (PropertiesAction.class), }; else return new SystemAction[] { SystemAction.get (CreateVariableAction.class), null, SystemAction.get (ToolsAction.class), SystemAction.get (PropertiesAction.class), }; } /** Helper method, creates properties common to variable * and watch contexts. */ void createCommonProperties ( final ResourceBundle bundle, final Sheet.Set ps ) { ps.put (new PropertySupport.ReadOnly ( Watch.PROP_TYPE, String.class, getLocalizedString ("PROP_watch_type"), getLocalizedString ("HINT_watch_type") ) { public Object getValue () { return variable.getType (); } }); ps.put (new PropertySupport.ReadOnly ( PROP_INNER_TYPE, String.class, getLocalizedString ("PROP_watch_inner_type"), getLocalizedString ("HINT_watch_inner_type") ) { public Object getValue () { return variable.getInnerType (); } }); ps.put (new PropertySupport.ReadOnly ( PROP_MODIFIERS, String.class, getLocalizedString ("PROP_watch_modifiers"), getLocalizedString ("HINT_watch_modifiers") ) { public Object getValue () { return variable.getModifiers (); } }); ps.put (new PropertySupport.ReadWrite ( Watch.PROP_AS_TEXT, String.class, getLocalizedString ("PROP_watch_value"), getLocalizedString ("HINT_watch_value") ) { public Object getValue () { return variable.getAsText (); } public void setValue (Object val) throws IllegalArgumentException { try { variable.setAsText ((String)val); } catch (ClassCastException e) { throw new IllegalArgumentException (); } catch (DebuggerException e) {} } }); if (isArray) { ps.put (new PropertySupport.ReadWrite ( PROP_BASE_INDEX, Integer.TYPE, getLocalizedString ("PROP_base_index"), getLocalizedString ("HINT_base_index") ) { public Object getValue () { return new Integer (baseIndex); } public void setValue (Object val) throws IllegalArgumentException { try { int x = ((Integer)val).intValue (); if (x < 0) throw new ClassCastException (); baseIndex = x; if (isArray) changeChildren (); // firePropertyChange (PROP_BASE_INDEX, null, null); } catch (ClassCastException e) { new IllegalArgumentException (); } } }); ps.put (new PropertySupport.ReadWrite ( PROP_DISPLAYED_LENGTH, Integer.TYPE, getLocalizedString ("PROP_displayed_length"), getLocalizedString ("HINT_displayed_length") ) { public Object getValue () { return new Integer (displayedLength); } public void setValue (Object val) throws IllegalArgumentException { try { int x = ((Integer)val).intValue (); if (x < 0) throw new ClassCastException (); displayedLength = x; if (isArray) changeChildren (); // firePropertyChange (PROP_DISPLAYED_LENGTH, null, null); } catch (ClassCastException e) { new IllegalArgumentException (); } } }); } } /** * Variable can be removed. * * @return <CODE>true</CODE> */ public boolean canDestroy () { return true; } /** * Removes the Variable from its parent and deletes it. */ public void destroy () throws IOException { super.destroy (); disposeVariable (); } // GetVariableCookie implementation .......................................... /** * Returns variable instance. */ public AbstractVariable getVariable () { return variable; } // other methods ............................................................. /** * @return localized string. */ static String getLocalizedString (String s) { if (bundle == null) bundle = NbBundle.getBundle (VariableNode.class); return bundle.getString (s); } /** * Disposes resources of this variable an sub-variables. */ private void disposeVariable () throws IOException { variable.removePropertyChangeListener (pcl); variable = null; if (getChildren () == Children.LEAF) return; VariableContextChildren myChildren = (VariableContextChildren) getChildren (); if (!myChildren.initialized) return; Node[] n = myChildren.getNodes (); int i, k = n.length; for (i = 0; i < k; i++) ((VariableNode) n [i]).disposeVariable (); } /** * Returns human presentable name of this variable containing * informations about value or valide. * * @return human presentable name of this variable. */ public String getName () { String name = variable.getVariableName (); if ((name == null) || (debugger == null)) return "???"; // NOI18N if (debugger.getState () == Debugger.DEBUGGER_NOT_RUNNING) return name + " " + getLocalizedString ("CTL_NoSession"); String type = variable.getType (); String innerType = variable.getInnerType (); String value = variable.getAsText (); if (type == null) if (value == null) if (variable.isObject ()) return name + " = null"; // NOI18N else return name + " " + getLocalizedString ("CTL_NotInitialized"); else return name + " = >" + value + "<"; // NOI18N if (variable.isObject ()) { if (type.equals (innerType)) return name + " = (" + innerType + ") " + value; // NOI18N else return name + " = (" + type + ") (" + innerType + ") " + value; // NOI18N } else return name + " = (" + type + ") " + value; // NOI18N } public void createVariable () { variableHome.createVariable (variable); } /** * Sets display name and fires property change. */ void parameterChanged (PropertyChangeEvent e) { if (variable.isArray () != isArray) { isArray = !isArray; createProperties (); } String s = getName (); setDisplayName (s); setName (s); changeChildren (); firePropertyChange ( e.getPropertyName (), e.getOldValue (), e.getNewValue () ); } /** * Sets current variable fields. */ void changeChildren () { // set fields of this variable as keys into our children if (getChildren() == Children.LEAF) { Node n = getParentNode (); if (n == null) return; AbstractVariable v = getVariable (); if (!v.isLeaf ()) { LeafRefresher parentChildren = (LeafRefresher) n.getChildren (); parentChildren.refreshMyKey (v); } return; } VariableContextChildren myChildren = (VariableContextChildren) getChildren (); if (!myChildren.initialized) return; AbstractVariable [] fields = variable.getFields (); if (isArray) { int length = Math.min (displayedLength, fields.length - baseIndex); AbstractVariable [] v = new AbstractVariable [length]; System.arraycopy (fields, baseIndex, v, 0, length); fields = v; } myChildren.setMyKeys (fields); } // innerclasses .............................................................. /** Special subnodes (children) for variable node */ private static final class VariableContextChildren extends Children.Keys implements LeafRefresher { /** Where to add variables. */ private VariableHome variableHome; private boolean initialized = false; VariableContextChildren (VariableHome variableHome) { this.variableHome = variableHome; } /** Initializes children. */ protected void addNotify () { initialized = true; ((VariableNode) getNode ()).changeChildren (); } /** Creates nodes for given key. * @param key the key that is used * @return array of nodes representing the key */ protected Node[] createNodes (Object key) { return new Node[] { new VariableNode (variableHome, (AbstractVariable)key) }; } /** Accessor for VariableNode outer class */ private void setMyKeys (Object[] keys) { setKeys(keys); } // interface LeafRefresher /** Accessor for VariableNode class */ public void refreshMyKey (Object key) { refreshKey (key); } } // end of VariableContextChildren inner class } /* * Log * 14 Gandalf-post-FCS1.12.3.0 3/28/00 Daniel Prusa * 13 Gandalf 1.12 1/17/00 Daniel Prusa setAsText method throws * DebuggerException * 12 Gandalf 1.11 1/14/00 Daniel Prusa NOI18N * 11 Gandalf 1.10 1/13/00 Daniel Prusa NOI18N * 10 Gandalf 1.9 1/4/00 Jan Jancura Use trim () on user * input. * 9 Gandalf 1.8 1/4/00 Daniel Prusa enabling/disabling of * Create fixed watch action * 8 Gandalf 1.7 12/20/99 Daniel Prusa Bug 4895 - Update of * watches after creating and assining a new instance into variable * previously containing null value. * 7 Gandalf 1.6 11/8/99 Jan Jancura Somma classes renamed * 6 Gandalf 1.5 11/5/99 Jan Jancura Default action updated * 5 Gandalf 1.4 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 4 Gandalf 1.3 10/11/99 Jan Jancura Bug in refreshing of * watches * 3 Gandalf 1.2 9/28/99 Jan Jancura * 2 Gandalf 1.1 9/15/99 Jan Jancura * 1 Gandalf 1.0 8/17/99 Jan Jancura * $ * Beta Change History: * 0 Tuborg 0.15 --/--/98 Jan Formanek popup menu improved */